package com.xiaozhen.common.core.utils;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SCPClient;
import ch.ethz.ssh2.SCPOutputStream;
import com.jcraft.jsch.*;
import com.xiaozhen.common.core.constant.Constants;
import com.xiaozhen.common.core.domain.AjaxResult;
import com.xiaozhen.common.core.domain.ScpConnectEntity;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * HISTORY
 *
 * @author zhenweisheng
 * @date 2021/12/2 10:08
 * @description:
 */
@Configuration
public class FileUploadUtils {

    @Value("${remoteServer.url}")
    private String remoteUrl;

    @Value("${remoteServer.path}")
    private String targetPath;

    @Value("${remoteServer.password}")
    private String passWord;

    @Value("${remoteServer.username}")
    private String userName;

    public AjaxResult uploadFile(MultipartFile file) {
        String hostIp = IpUtils.getHostIp();
        AjaxResult ajaxResult;
        //构造远程文件的文件名
        String fileSuffix = getExtension(file);
        String remoteFileName = getRemoteFileName(hostIp, fileSuffix);
        //如果是本地IP
        if (hostIp.contains(remoteUrl)) {
            ajaxResult = uploadFileLocal(file, targetPath, remoteFileName);
        } else {
            ajaxResult = uploadFileRemote(file, targetPath, remoteFileName);
            //toFile.delete();//删除临时文件
        }
        return ajaxResult;
    }


    public AjaxResult uploadFileLocal(MultipartFile file, String targetPath, String remoteFileName) {
        int code = Constants.SUCCESS;
        String message = "上传成功";
        String data = null;
        File fileDir = new File(targetPath);
        if (!fileDir.exists()) {
            //如果没有目录应该创建目录
            fileDir.mkdirs();
        }
        String path = targetPath + remoteFileName;
        //文件实现上传
        try {
            file.transferTo(new File(path));
            data = remoteFileName;
        } catch (IOException e) {
            code = Constants.FAIL;
            message = e.getMessage();
            e.printStackTrace();
        }
        return new AjaxResult(code, message, data);
    }


    public AjaxResult uploadFileRemote(MultipartFile file, String targetPath, String remoteFileName) {
        ScpConnectEntity scpConnectEntity = new ScpConnectEntity();
        scpConnectEntity.setTargetPath(targetPath);
        scpConnectEntity.setUrl(remoteUrl);
        scpConnectEntity.setPassWord(passWord);
        scpConnectEntity.setUserName(userName);
        int code;
        String message;
        String data = null;
        try {
            if (remoteFileName == null || "".equals(remoteFileName.trim())) {
                throw new IllegalArgumentException("远程服务器新建文件名不能为空!");
            }
            remoteUploadFile(scpConnectEntity, file, remoteFileName);
            code = Constants.SUCCESS;
            message = "上传成功";
            data = remoteFileName;
        } catch (IllegalArgumentException e) {
            code = Constants.FAIL;
            message = e.getMessage();
        } catch (JSchException e) {
            code = Constants.FAIL;
            message = e.getMessage();
        } catch (IOException e) {
            code = Constants.FAIL;
            message = e.getMessage();
        } catch (Exception e) {
            throw e;
        } catch (Error e) {
            code = Constants.FAIL;
            message = e.getMessage();
        }
        return new AjaxResult(code, message, data);
    }


    private void remoteUploadFile(ScpConnectEntity scpConnectEntity, MultipartFile file,
                                  String remoteFileName) throws JSchException, IOException {

        Connection connection = null;
        ch.ethz.ssh2.Session session = null;
        SCPOutputStream scpo = null;

        try {
            createDir(scpConnectEntity);
        } catch (JSchException e) {
            throw e;
        }

        try {
            connection = new Connection(scpConnectEntity.getUrl());
            connection.connect();

            if (!connection.authenticateWithPassword(scpConnectEntity.getUserName(), scpConnectEntity.getPassWord())) {
                throw new RuntimeException("SSH连接服务器失败");
            }
            session = connection.openSession();

            SCPClient scpClient = connection.createSCPClient();

            byte[] fileBytes = file.getBytes();
            scpo = scpClient.put(remoteFileName, fileBytes.length, scpConnectEntity.getTargetPath(), "0666");
            scpo.write(fileBytes, 0, fileBytes.length);
        } catch (IOException e) {
            throw new IOException("SSH上传文件至服务器出错" + e.getMessage());
        } finally {
            if (null != scpo) {
                try {
                    scpo.flush();
                    scpo.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != session) {
                session.close();
            }
            if (null != connection) {
                connection.close();
            }
        }
    }


    private boolean createDir(ScpConnectEntity scpConnectEntity) throws JSchException {

        JSch jsch = new JSch();
        com.jcraft.jsch.Session sshSession = null;
        Channel channel = null;
        try {
            sshSession = jsch.getSession(scpConnectEntity.getUserName(), scpConnectEntity.getUrl(), 22);
            sshSession.setPassword(scpConnectEntity.getPassWord());
            sshSession.setConfig("StrictHostKeyChecking", "no");
            sshSession.connect();
            channel = sshSession.openChannel("sftp");
            channel.connect();
        } catch (JSchException e) {
            e.printStackTrace();
            throw new JSchException("SFTP连接服务器失败" + e.getMessage());
        }
        ChannelSftp channelSftp = (ChannelSftp) channel;
        if (isDirExist(scpConnectEntity.getTargetPath(), channelSftp)) {
            channel.disconnect();
            channelSftp.disconnect();
            sshSession.disconnect();
            return true;
        } else {
            String pathArry[] = scpConnectEntity.getTargetPath().split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArry) {
                if (path.equals("")) {
                    continue;
                }
                filePath.append(path + "/");
                try {
                    if (isDirExist(filePath.toString(), channelSftp)) {
                        channelSftp.cd(filePath.toString());
                    } else {
                        // 建立目录
                        channelSftp.mkdir(filePath.toString());
                        // 进入并设置为当前目录
                        channelSftp.cd(filePath.toString());
                    }
                } catch (SftpException e) {
                    e.printStackTrace();
                    throw new JSchException("SFTP无法正常操作服务器" + e.getMessage());
                }
            }
        }
        channel.disconnect();
        channelSftp.disconnect();
        sshSession.disconnect();
        return true;
    }

    private boolean isDirExist(String directory, ChannelSftp channelSftp) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = channelSftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    public String getRemoteFileName(String ip, String fileSuffix) {
        String[] splitIp = ip.split(".");
        StringBuffer stringBuffer = new StringBuffer();
        //IP
        for (int i = 0; i < splitIp.length; i++) {
            stringBuffer.append(splitIp[i]);
        }
        //时间
        LocalDateTime now = LocalDateTime.now();
        stringBuffer.append(now.getYear());
        stringBuffer.append(now.getMonthValue());
        stringBuffer.append(now.getDayOfMonth());
        stringBuffer.append(now.getHour());
        stringBuffer.append(now.getMinute());
        stringBuffer.append(now.getSecond());
        stringBuffer.append(UUID.randomUUID().toString().replaceAll("_", ""), 0, 4);
        stringBuffer.append(".").append(fileSuffix);
        return stringBuffer.toString();
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static final String getExtension(MultipartFile file) {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension)) {
            extension = MimeTypeUtils.getExtension(file.getContentType());
        }
        return extension;
    }
}
